#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
    Module Documentation 
    here
"""

# Created by  : Zhang Chengdong
# Create Date : 2024/11/27 16:02
# Version = v0.1.0

__author__ = "Zhang Chengdong"
__copyright__ = "Copyright 2024. Large scale model"
__credits__ = ['Zhang Chengdong', 'Xu Zhiqiang', 'Lu Yuxing']

__liscence__ = "MIT"
__version__ = "1.0.1"
__maintainer__ = "Zhang Chengdong"
__status__ = "Production"

# -*- coding: utf-8 -*-

import os

os.environ["CRYPTOGRAPHY_OPENSSL_NO_LEGACY"] = "1"
import binascii
import argparse
import json
from linearmodel.log import log_record
import traceback
from linearmodel import config
from linearmodel import predict_strength
from collections import ChainMap
from nonmodel.predict_data import predict_main
from nonmodel import predict_data


def linear_model_predict(data, model_path):
    """
    # 线性模型预测
    :param data:
    :param model_path:
    :return:
    """


def api(params, log_obj):
    tenant_id = log_obj["app_tenant_id"]
    config.current_tenant_id = tenant_id
    if params["api_type"] == "predict_cement_strength":
        data = params["data"]
        model_code = f"CI_10001194-{data['cement_mill']}-{data['cement_type']}"
        data = predict_strength.transform_ci_to_nl(data, config.master_data)
        # 线性模型
        linear_result = predict_strength.cement_strength_predict(model_code, data)

        # 非线性模型
        nonlinear_info = nonlinear_predict_part(data, model_code)
        res = {'status': 'success', 'results': {**linear_result, **nonlinear_info}}
        return res
    else:
        raise Exception("api_type error")


def determine_model_use(data: dict):
    """
    判断数据应该使用哪一个模型   cement_real_strength_1d   cement_real_strength_3d
    :param data:
    :return:
    """
    model_type_suffix = {
        "model3_1d": {"model_name": "model3_1d", "use_name": "with_real_strength_1d", "code": "CI_10001103"},
        "model3_n1d": {"model_name": "model3_n1d", "use_name": "no_real_strength", "code": "CI_10001103"},
        "model28_1d": {"model_name": "model28_1d", "use_name": "with_real_strength_1d", "code": "CI_10001104"},
        # 有一天，无3天 水泥实测值
        "model28_n1d": {"model_name": "model28_n1d", "use_name": "no_real_strength", "code": "CI_10001104"},
        # 无一天，无3天 水泥实测值
        "model28_3d": {"model_name": "model28_3d", "use_name": "with_real_strength_3d", "code": "CI_10001104"},
        # 有一天，有3天 水泥实测值
    }
    if data['current_data']['cement_real_strength_1d'] == "":
        data['current_data']['cement_real_strength_1d'] = None
    if data['current_data']['cement_real_strength_3d'] == "":
        data['current_data']['cement_real_strength_3d'] = None

    have_one = data['current_data'].get("cement_real_strength_1d", None)
    have_three = data['current_data'].get("cement_real_strength_3d", None)

    if have_one is None and have_three is None:
        info = {
            "model3_n1d": {"model_name": "model3_n1d", "use_name": "no_real_strength", "code": "CI_10001103"},
            "model28_n1d": {"model_name": "model28_n1d", "use_name": "no_real_strength", "code": "CI_10001104"}
        }
        not_have_data_type = {'with_real_strength_1d': {}, 'with_real_strength_3d': {}}
    elif have_one is not None and have_three is None:
        info = {
            "model3_n1d": {"model_name": "model3_n1d", "use_name": "no_real_strength", "code": "CI_10001103"},
            "model28_n1d": {"model_name": "model28_n1d", "use_name": "no_real_strength", "code": "CI_10001104"},
            "model3_1d": {"model_name": "model3_1d", "use_name": "with_real_strength_1d", "code": "CI_10001103"},
            "model28_1d": {"model_name": "model28_1d", "use_name": "with_real_strength_1d", "code": "CI_10001104"}
        }
        not_have_data_type = {'with_real_strength_3d': {}}
    elif have_one is None and have_three is not None:
        info = {
            "model3_n1d": {"model_name": "model3_n1d", "use_name": "no_real_strength", "code": "CI_10001103"},
            "model28_n1d": {"model_name": "model28_n1d", "use_name": "no_real_strength", "code": "CI_10001104"},
            "model28_3d": {"model_name": "model28_3d", "use_name": "with_real_strength_3d", "code": "CI_10001104"},
        }
        not_have_data_type = {'with_real_strength_1d': {}}
    else:
        info = {
            "model3_1d": {"model_name": "model3_1d", "use_name": "with_real_strength_1d", "code": "CI_10001103"},
            "model3_n1d": {"model_name": "model3_n1d", "use_name": "no_real_strength", "code": "CI_10001103"},
            "model28_1d": {"model_name": "model28_1d", "use_name": "with_real_strength_1d", "code": "CI_10001104"},
            "model28_n1d": {"model_name": "model28_n1d", "use_name": "no_real_strength", "code": "CI_10001104"},
            "model28_3d": {"model_name": "model28_3d", "use_name": "with_real_strength_3d", "code": "CI_10001104"},
        }
        not_have_data_type = {}
    return info, not_have_data_type


def nonlinear_predict_part(data: dict, model_code: str = "CI_10001194-CI_10001073-CI_10001091"):
    """
    非线形模型预测部分
    :param data:
    :param model_code:
    :return
    """
    current_dir = os.path.dirname(os.path.abspath(__file__))
    parent_dir = os.path.dirname(current_dir)
    # save_model_path = os.path.join(parent_dir, "models")
    save_model_path = "./models"
    model_result = {}
    model_type_suffix, not_have_data_type = determine_model_use(data)
    for item in model_type_suffix:
        model_info = {
            "model_type": item,
            "model_path": os.path.join(save_model_path, "CatBoost", model_code + "_{}.pkl".format(item)),
            "first_suffix": model_type_suffix[item]['use_name'],
            "second_suffix": model_type_suffix[item]['code']
        }
        y_pred_info = predict_main(data, model_info)
        if list(y_pred_info.keys())[0] not in model_result:
            model_result.update(y_pred_info)
        else:
            first_key_name = list(y_pred_info.keys())[0]
            model_result[first_key_name].update(y_pred_info[first_key_name])
    model_result.update(not_have_data_type)
    return {"nonlinear": model_result}


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('--params', type=str, required=True, help='Input params', default="123")
    parser.add_argument('--common_params', type=str, required=False, help='Input params', default="7d7d")

    args = parser.parse_args()

    json_str = binascii.unhexlify(args.params)
    app_params = binascii.unhexlify(args.common_params)

    json_obj = json.loads(json_str)
    log_obj = json.loads(app_params)
    log_record("start", "", f"json_obj:{json_obj}  log_obj:{log_obj}", log_obj)
    try:
        data = api(json_obj, log_obj)
        log_record("running", "", f"params: {data}", log_obj)
        result = {'status': 'success', 'errorCode': 0, 'errorMsg': '', 'data': data}
        log_record("success", "", f"params: {result}", log_obj)
    except Exception as e:
        error_message = traceback.format_exc()
        result = {'status': 'failure', 'errorCode': -1, 'errorMsg': error_message}
        log_record("failure", "", f"params: {result}", log_obj)

    print(result)
